package com.sss.otep.client.proxy;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.client.core.WebServiceTemplate;
import org.springframework.ws.transport.http.HttpsUrlConnectionMessageSender;

public abstract class AbstractSSLClient {
	private static final Logger log = LoggerFactory
			.getLogger(AbstractSSLClient.class);
	protected static final String KEY_MANAGER_ALGORITHM = "SunX509";
	protected static final String TRUST_ALGORITHM = "PKIX";
	protected static final String JKS = "JKS";

	public AbstractSSLClient() {
		super();
	}

	@Autowired
	private WebServiceTemplate webServiceTemplate;
	private boolean performed = false;

	public abstract File getKeyStoreFile();

	public abstract String getKeyStorePass();

	public abstract File getTrustStoreFile();

	public abstract String getTrustStorePass();

	/**
	 * 
	 * @return
	 * @throws KeyStoreException
	 * @throws NoSuchAlgorithmException
	 * @throws CertificateException
	 * @throws FileNotFoundException
	 * @throws IOException
	 * @throws UnrecoverableKeyException
	 */
	protected HttpsUrlConnectionMessageSender buildHttpsMessageSender()
			throws KeyStoreException, NoSuchAlgorithmException,
			CertificateException, FileNotFoundException, IOException,
			UnrecoverableKeyException {

		HttpsUrlConnectionMessageSender msgSender = new HttpsUrlConnectionMessageSender();

		KeyManagerFactory keyManagerFactory = this.getKeyManagerFactory(
				getKeyStoreFile(), getKeyStorePass());

		TrustManagerFactory trustManagerFactory = this.getTrustManagerFactory(
				getTrustStoreFile(), getTrustStorePass());

		msgSender.setKeyManagers(keyManagerFactory.getKeyManagers());
		msgSender.setTrustManagers(trustManagerFactory.getTrustManagers());

		msgSender.setSecureRandom(new SecureRandom());
		msgSender.setSslProtocol("TLS");
		return msgSender;
	}
	protected WebServiceTemplate performWebServiceTemplate() {
		return this.webServiceTemplate;
	}
	protected WebServiceTemplate performSSLWebServiceTemplate() {
		log.info("Setting up https client with client keystore and truststore");
		if (webServiceTemplate != null && !isPerformed()) {
			try {
				webServiceTemplate.setMessageSender(buildHttpsMessageSender());
				this.performed = true;
			} catch (UnrecoverableKeyException e) {
				log.error("Unrecoverable key exception..!!", e.getMessage());
			} catch (KeyStoreException e) {
				log.error("Keystore exception..!!", e.getMessage());
			} catch (NoSuchAlgorithmException e) {
				log.error("No such algorithm exception..!!", e.getMessage());
			} catch (CertificateException e) {
				log.error("Certificate exception..!!", e.getMessage());
			} catch (FileNotFoundException e) {
				log.error("File not found exception..!!", e.getMessage());
			} catch (IOException e) {
				log.error("IO exception..!!", e.getMessage());
			}
		}
		return webServiceTemplate;
	}

	private boolean isPerformed() {	
		return performed ;
	}

	/**
	 * 
	 * @param file
	 * @param trustpass
	 * @return
	 * @throws KeyStoreException
	 * @throws NoSuchAlgorithmException
	 * @throws CertificateException
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	protected TrustManagerFactory getTrustManagerFactory(File file,
			String trustpass) throws KeyStoreException,
			NoSuchAlgorithmException, CertificateException,
			FileNotFoundException, IOException {

		return getTrustManagerFactory(file, trustpass.toCharArray());
	}

	/**
	 * 
	 * @param file
	 * @param trustpass
	 * @return
	 * @throws KeyStoreException
	 * @throws IOException
	 * @throws NoSuchAlgorithmException
	 * @throws CertificateException
	 * @throws FileNotFoundException
	 */
	protected TrustManagerFactory getTrustManagerFactory(File file,
			char[] trustpass) throws KeyStoreException, IOException,
			NoSuchAlgorithmException, CertificateException,
			FileNotFoundException {

		/* TRUST STORE MANAGER */
		KeyStore trustStore = KeyStore.getInstance(JKS);
		trustStore.load(new FileInputStream(file), trustpass);

		TrustManagerFactory trustManagerFactory = TrustManagerFactory
				.getInstance(TRUST_ALGORITHM);
		trustManagerFactory.init(trustStore);
		return trustManagerFactory;
	}

	/**
	 * 
	 * @param file
	 * @param keystorepass
	 * @return
	 * @throws UnrecoverableKeyException
	 * @throws KeyStoreException
	 * @throws NoSuchAlgorithmException
	 * @throws CertificateException
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	protected KeyManagerFactory getKeyManagerFactory(File file,
			String keystorepass) throws UnrecoverableKeyException,
			KeyStoreException, NoSuchAlgorithmException, CertificateException,
			FileNotFoundException, IOException {

		return getKeyManagerFactory(file, keystorepass.toCharArray());
	}

	/**
	 * 
	 * @param file
	 * @param keystorepass
	 * @return
	 * @throws KeyStoreException
	 * @throws IOException
	 * @throws NoSuchAlgorithmException
	 * @throws CertificateException
	 * @throws FileNotFoundException
	 * @throws UnrecoverableKeyException
	 */
	protected KeyManagerFactory getKeyManagerFactory(File file,
			char[] keystorepass) throws KeyStoreException, IOException,
			NoSuchAlgorithmException, CertificateException,
			FileNotFoundException, UnrecoverableKeyException {

		/* KEY STORE MANAGER */
		KeyStore keyStore = KeyStore.getInstance(JKS);
		keyStore.load(new FileInputStream(file), keystorepass);

		KeyManagerFactory keyManagerFactory = KeyManagerFactory
				.getInstance(KEY_MANAGER_ALGORITHM);
		keyManagerFactory.init(keyStore, keystorepass);
		return keyManagerFactory;
	}


}